home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Libraries / Apache 1.0 / src / http_request.c < prev    next >
Text File  |  1995-12-04  |  20KB  |  692 lines

  1.  
  2. /* ====================================================================
  3.  * Copyright (c) 1995 The Apache Group.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer. 
  11.  *
  12.  * 2. Redistributions in binary form must reproduce the above copyright
  13.  *    notice, this list of conditions and the following disclaimer in
  14.  *    the documentation and/or other materials provided with the
  15.  *    distribution.
  16.  *
  17.  * 3. All advertising materials mentioning features or use of this
  18.  *    software must display the following acknowledgment:
  19.  *    "This product includes software developed by the Apache Group
  20.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  21.  *
  22.  * 4. The names "Apache Server" and "Apache Group" must not be used to
  23.  *    endorse or promote products derived from this software without
  24.  *    prior written permission.
  25.  *
  26.  * 5. Redistributions of any form whatsoever must retain the following
  27.  *    acknowledgment:
  28.  *    "This product includes software developed by the Apache Group
  29.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  30.  *
  31.  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
  32.  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  33.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  34.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
  35.  * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  36.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  37.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  38.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  39.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  40.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  41.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  42.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  43.  * ====================================================================
  44.  *
  45.  * This software consists of voluntary contributions made by many
  46.  * individuals on behalf of the Apache Group and was originally based
  47.  * on public domain software written at the National Center for
  48.  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
  49.  * For more information on the Apache Group and the Apache HTTP server
  50.  * project, please see <http://www.apache.org/>.
  51.  *
  52.  */
  53.  
  54.  
  55. /*
  56.  * http_request.c: functions to get and process requests
  57.  * 
  58.  * Rob McCool 3/21/93
  59.  *
  60.  * Thoroughly revamped by rst for Shambhala.  NB this file reads
  61.  * best from the bottom up.
  62.  * 
  63.  */
  64.  
  65. #define CORE_PRIVATE
  66. #include "httpd.h"
  67. #include "http_config.h"
  68. #include "http_request.h"
  69. #include "http_core.h"
  70. #include "http_protocol.h"
  71. #include "http_log.h"
  72. #include "http_main.h"
  73.  
  74. /*****************************************************************
  75.  *
  76.  * Getting and checking directory configuration.  Also checks the
  77.  * FollowSymlinks and FollowSymOwner stuff, since this is really the
  78.  * only place that can happen (barring a new mid_dir_walk callout).
  79.  *
  80.  * We can't do it as an access_checker module function which gets
  81.  * called with the final per_dir_config, since we could have a directory
  82.  * with FollowSymLinks disabled, which contains a symlink to another
  83.  * with a .htaccess file which turns FollowSymLinks back on --- and
  84.  * access in such a case must be denied.  So, whatever it is that
  85.  * checks FollowSymLinks needs to know the state of the options as
  86.  * they change, all the way down.
  87.  */
  88.  
  89. int check_symlinks (char *d, int opts)
  90. {
  91.     struct stat lfi, fi;
  92.     char *lastp;
  93.     int res;
  94.   
  95.     if (opts & OPT_SYM_LINKS) return OK;
  96.  
  97.     /* Strip trailing '/', if any, off what we're checking; trailing
  98.      * slashes make some systems follow symlinks to directories even in
  99.      * lstat().  After we've done the lstat, put it back.  Also, don't
  100.      * bother checking '/' at all...
  101.      *
  102.      * Note that we don't have to worry about multiple slashes here
  103.      * because of no2slash() below...
  104.      */
  105.  
  106.     lastp = d + strlen(d) - 1;
  107.     if (lastp == d) return OK;    /* Root directory, '/' */
  108.     
  109.     if (*lastp == '/') *lastp = '\0';
  110.     else lastp = NULL;
  111.     
  112.     res = lstat (d, &lfi);
  113.  
  114.     if (lastp) *lastp = '/';
  115.     
  116.     /* Note that we don't reject accesses to nonexistent files (multiviews
  117.      * or the like may cons up a way to run the transaction anyway)...
  118.      */
  119.             
  120.     if (!(res >= 0) || !S_ISLNK(lfi.st_mode)) return OK;
  121.  
  122.     /* OK, it's a symlink.  May still be OK with OPT_SYM_OWNER */
  123.     
  124.     if (!(opts & OPT_SYM_OWNER)) return FORBIDDEN;
  125.     
  126.     if (stat (d, &fi) < 0) return FORBIDDEN;
  127.     
  128.     return (fi.st_uid == lfi.st_uid) ? OK : FORBIDDEN;
  129. }
  130.     
  131. /* Dealing with the file system to get PATH_INFO
  132.  */
  133.  
  134. void get_path_info(request_rec *r)
  135. {
  136.     char *cp;
  137.     char *path = r->filename;
  138.     char *end = &path[strlen(path)];
  139.     char *last_cp = NULL;
  140.     int rv;
  141.  
  142.     /* Advance over trailing slashes ... NOT part of filename */
  143.  
  144.     for (cp = end; cp > path && cp[-1] == '/'; --cp)
  145.     continue;
  146.     
  147.     while (cp > path) {
  148.       
  149.     /* See if the pathname ending here exists... */
  150.       
  151.     *cp = '\0';
  152.     rv = stat(path, &r->finfo);
  153.     if (cp != end) *cp = '/';
  154.       
  155.     if (!rv) {
  156.  
  157.         /* Aha!  Found something.  If it was a directory, we will
  158.          * search contents of that directory for a multi_match, so
  159.          * the PATH_INFO argument starts with the component after that.
  160.          */
  161.     
  162.         if (S_ISDIR(r->finfo.st_mode) && last_cp) {
  163.             r->finfo.st_mode = 0; /* No such file... */
  164.         cp = last_cp;
  165.         }
  166.     
  167.         r->path_info = pstrdup (r->pool, cp);
  168.         *cp = '\0';
  169.         return;
  170.     }
  171.     else {
  172.         last_cp = cp;
  173.     
  174.         while (--cp > path && *cp != '/')
  175.         continue;
  176.  
  177.         while (cp > path && cp[-1] == '/')
  178.         --cp;
  179.     }
  180.     }
  181. }
  182.  
  183. int directory_walk (request_rec *r)
  184. {
  185.     core_server_config *sconf = get_module_config (r->server->module_config,
  186.                            &core_module);
  187.     array_header *sec_array = copy_array (r->pool, sconf->sec);
  188.     
  189.     core_dir_config **sec = (core_dir_config **)sec_array->elts;
  190.     int num_sec = sec_array->nelts;
  191.     void *per_dir_defaults = r->server->lookup_defaults;
  192.     char *test_filename = pstrdup (r->pool, r->filename);
  193.  
  194.     int num_dirs, res;
  195.     int i;
  196.  
  197.     /* Go down the directory hierarchy.  Where we have to check for symlinks,
  198.      * do so.  Where a .htaccess file has permission to override anything,
  199.      * try to find one.  If either of these things fails, we could poke
  200.      * around, see why, and adjust the lookup_rec accordingly --- this might
  201.      * save us a call to get_path_info (with the attendant stat()s); however,
  202.      * for the moment, that's not worth the trouble.
  203.      */
  204.  
  205.     no2slash (test_filename);
  206.     num_dirs = count_dirs(test_filename);
  207.     get_path_info (r);
  208.     
  209.     if (S_ISDIR (r->finfo.st_mode)) ++num_dirs;
  210.  
  211.     for (i = 1; i <= num_dirs; ++i) {
  212.         core_dir_config *core_dir =
  213.       (core_dir_config *)get_module_config(per_dir_defaults, &core_module);
  214.     int allowed_here = core_dir->opts;
  215.     int overrides_here = core_dir->override;
  216.         void *this_conf = NULL, *htaccess_conf = NULL;
  217.     char *this_dir = make_dirstr (r->pool, test_filename, i);
  218.     char *config_name = make_full_path(r->pool, this_dir,
  219.                        sconf->access_name);
  220.     int j;
  221.       
  222.     /* Do symlink checks first, because they are done with the
  223.      * permissions appropriate to the *parent* directory...
  224.      */
  225.     
  226.     if ((res = check_symlinks (this_dir, allowed_here)))
  227.     {
  228.         log_reason("Symbolic link not allowed", this_dir, r);
  229.         return res;
  230.     }
  231.     
  232.     /* Begin *this* level by looking for matching <Directory> sections from
  233.      * access.conf.
  234.      */
  235.     
  236.     for (j = 0; j < num_sec; ++j) {
  237.         void *entry_config = sec[j];
  238.         core_dir_config *entry_core;
  239.         char *entry_dir;
  240.  
  241.         if (!entry_config) continue;
  242.         
  243.         entry_core =
  244.           (core_dir_config *)get_module_config(entry_config, &core_module);
  245.         entry_dir = entry_core->d;
  246.     
  247.         if (is_matchexp(entry_dir) && !strcmp_match(this_dir, entry_dir)) {
  248.         /* Don't try this wildcard again --- if it ends in '*'
  249.          * it'll match again, and subdirectories won't be able to
  250.          * override it...
  251.          */
  252.         sec[j] = NULL;    
  253.             this_conf = entry_config;
  254.         }
  255.         else if (!strcmp (this_dir, entry_dir))
  256.             this_conf = entry_config;
  257.     }
  258.  
  259.     if (this_conf)
  260.     {
  261.         per_dir_defaults =
  262.             merge_per_dir_configs (r->pool, per_dir_defaults, this_conf);
  263.         core_dir =(core_dir_config *)get_module_config(per_dir_defaults,
  264.                                &core_module);
  265.     }
  266.     overrides_here = core_dir->override;
  267.  
  268.     /* If .htaccess files are enabled, check for one.
  269.      */
  270.     
  271.     if (overrides_here) {
  272.         res = parse_htaccess (&htaccess_conf, r, overrides_here,
  273.                   this_dir, config_name);
  274.         if (res) return res;
  275.     }
  276.  
  277.     if (htaccess_conf)
  278.         per_dir_defaults =
  279.             merge_per_dir_configs (r->pool, per_dir_defaults,
  280.                        htaccess_conf);
  281.     
  282.     }
  283.  
  284.     r->per_dir_config = per_dir_defaults;
  285.  
  286.     if ((res = check_symlinks (r->filename, allow_options(r))))
  287.     {
  288.     log_reason("Symbolic link not allowed", r->filename, r);
  289.     return res;
  290.     }
  291.     
  292.     return OK;            /* Can only "fail" if access denied
  293.                  * by the symlink goop.
  294.                  */
  295. }
  296.  
  297. /*****************************************************************
  298.  *
  299.  * The sub_request mechanism.
  300.  *
  301.  * Fns to look up a relative URI from, e.g., a map file or SSI document.
  302.  * These do all access checks, etc., but don't actually run the transaction
  303.  * ... use run_sub_req below for that.  Also, be sure to use destroy_sub_req
  304.  * as appropriate if you're likely to be creating more than a few of these.
  305.  * (An early Shambhala version didn't destroy the sub_reqs used in directory
  306.  * indexing.  The result, when indexing a directory with 800-odd files in
  307.  * it, was massively excessive storage allocation).
  308.  *
  309.  * Note more manipulation of protocol-specific vars in the request
  310.  * structure...
  311.  */
  312.  
  313. request_rec *make_sub_request (request_rec *r)
  314. {
  315.     pool *rrp = make_sub_pool (r->pool);
  316.     request_rec *rr = pcalloc (rrp, sizeof (request_rec));
  317.     
  318.     rr->pool = rrp;
  319.     return rr;
  320. }
  321.  
  322. request_rec *sub_req_lookup_simple (char *new_file, request_rec *r)
  323. {
  324.     /* This handles the simple case, common to ..._lookup_uri and _file,
  325.      * of looking up another file in the same directory.
  326.      */
  327.     request_rec *rnew = make_sub_request (r);
  328.     pool *rnewp = rnew->pool;
  329.     int res;
  330.     
  331.     char *udir = make_dirstr(rnewp, r->uri, count_dirs(r->uri));
  332.     char *fdir = make_dirstr(rnewp, r->filename, count_dirs(r->filename));
  333.  
  334.     *rnew = *r;            /* Copy per_dir config, etc. */
  335.     rnew->pool = rnewp;
  336.     rnew->uri = make_full_path (rnewp, udir, new_file);
  337.     rnew->filename = make_full_path (rnewp, fdir, new_file);
  338.     set_sub_req_protocol (rnew, r);
  339.     
  340.     rnew->finfo.st_mode = 0;
  341.     
  342.     if ((res = check_symlinks (rnew->filename, allow_options (rnew))))
  343.     {
  344.         rnew->status = res;
  345.     }
  346.  
  347.     if (rnew->finfo.st_mode == 0 && stat (rnew->filename, &rnew->finfo) < 0)
  348.         rnew->finfo.st_mode = 0;
  349.  
  350.     if ((rnew->status == 200) && (res = find_types (rnew)))
  351.         rnew->status = res;
  352.     
  353.     if ((rnew->status == 200) && (res = run_fixups (rnew)))
  354.         rnew->status = res;
  355.     
  356.     return rnew;
  357. }
  358.  
  359. request_rec *sub_req_lookup_uri (char *new_file, request_rec *r)
  360. {
  361.     request_rec *rnew;
  362.     int res;
  363.     char *udir;
  364.     
  365.     rnew = make_sub_request (r);
  366.     rnew->connection = r->connection; 
  367.     rnew->server = r->server;
  368.     rnew->request_config = create_request_config (rnew->pool);
  369.     set_sub_req_protocol (rnew, r);
  370.     
  371.     if (new_file[0] == '/')
  372.     parse_uri(rnew, new_file);
  373.     else
  374.     {
  375.     udir = make_dirstr (rnew->pool, r->uri, count_dirs (r->uri));
  376.     udir = escape_uri(rnew->pool, udir); /* re-escape it */
  377.     parse_uri (rnew, make_full_path (rnew->pool, udir, new_file));
  378.     }
  379.     
  380.     res = unescape_url (rnew->uri);
  381.     if (res)
  382.     {
  383.     rnew->status = res;
  384.     return rnew;
  385.     }
  386.  
  387.     getparents (rnew->uri);
  388.     
  389.     res = translate_name(rnew);
  390.     if (res)
  391.     {
  392.     rnew->status = res;
  393.     return rnew;
  394.     }
  395.  
  396.     /* We could be clever at this point, and avoid calling directory_walk, etc.
  397.      * However, we'd need to test that the old and new filenames contain the
  398.      * same directory components, so it would require duplicating the start
  399.      * of translate_name.
  400.      * Maybe it would be easier to implement a cache for directory and
  401.      * .htaccess stats, or perhaps pass the old request to translate_name()
  402.      * for it to do the optimisation.
  403.      */
  404.     
  405.     if ((res = directory_walk (rnew))
  406.     || (!auth_type (rnew) ? 0 :
  407.          ((res = check_user_id (rnew)) || (res = check_auth (rnew))))
  408.     || (res = check_access (rnew))
  409.     || (res = find_types (rnew))
  410.     || (res = run_fixups (rnew))
  411.     )
  412.     {
  413.         rnew->status = res;
  414.     }
  415.  
  416.     return rnew;
  417. }
  418.  
  419. request_rec *sub_req_lookup_file (char *new_file, request_rec *r)
  420. {
  421.     request_rec *rnew;
  422.     int res;
  423.     char *fdir;
  424.     
  425.     /* Check for a special case... if there are no '/' characters in new_file
  426.      * at all, then we are looking at a relative lookup in the same directory.
  427.      * That means we don't have to redo any access checks.
  428.      */
  429.  
  430.     if (strchr (new_file, '/') == NULL) 
  431.         return sub_req_lookup_simple (new_file, r);
  432.  
  433.     rnew = make_sub_request (r);
  434.     fdir = make_dirstr (rnew->pool, r->filename, count_dirs (r->filename));
  435.     
  436.     rnew->connection = r->connection; /* For now... */
  437.     rnew->server = r->server;
  438.     rnew->request_config = create_request_config (rnew->pool);
  439.     set_sub_req_protocol (rnew, r);
  440.     
  441.     rnew->uri = "INTERNALLY GENERATED file-relative req";
  442.     rnew->filename = ((new_file[0] == '/') ?
  443.               new_file :
  444.               make_full_path (rnew->pool, fdir, new_file));
  445.     
  446.     if ((res = directory_walk (rnew))
  447.     || (res = check_access (rnew))
  448.     || (!auth_type (rnew) ? 0 :
  449.          ((res = check_user_id (rnew)) && (res = check_auth (rnew))))
  450.     || (res = find_types (rnew))
  451.     || (res = run_fixups (rnew))
  452.     )
  453.     {
  454.         rnew->status = res;
  455.     }
  456.  
  457.     return rnew;
  458. }
  459.  
  460. int run_sub_req (request_rec *r)
  461. {
  462.     int retval = invoke_handler (r);
  463.     finalize_sub_req_protocol (r);
  464.     return retval;
  465. }
  466.  
  467. void destroy_sub_req (request_rec *r)
  468. {
  469.     /* Reclaim the space */
  470.     destroy_pool (r->pool);
  471. }
  472.  
  473. /*****************************************************************
  474.  *
  475.  * Mainline request processing...
  476.  */
  477.  
  478. void die(int type, request_rec *r)
  479. {
  480.     int error_index = index_of_response (type);
  481.     char *custom_response = response_code_string(r, error_index);
  482.     int recursive_error = 0;
  483.     
  484.     /* The following takes care of Apache redirects to custom response URLs
  485.      * Note that if we are already dealing with the response to some other
  486.      * error condition, we just report on the original error, and give up on
  487.      * any attempt to handle the other thing "intelligently"...
  488.      */
  489.  
  490.     if (r->status != 200) {
  491.         recursive_error = type;
  492.  
  493.     while (r->prev && r->prev->status != 200)
  494.       r = r->prev; /* Get back to original error */
  495.     
  496.     type = r->status;
  497.     custom_response = NULL;    /* Do NOT retry the custom thing! */
  498.     }
  499.        
  500.     r->status = type;
  501.     
  502.     /* Two types of custom redirects --- plain text, and URLs.
  503.      * Plain text has a leading '"', so the URL code, here, is triggered
  504.      * on its absence
  505.      */
  506.     
  507.     if (custom_response && custom_response[0] != '"') {
  508.           
  509.         if (is_url(custom_response)) {
  510.         /* The URL isn't local, so lets drop through the rest of
  511.          * this apache code, and continue with the usual REDIRECT
  512.          * handler.  But note that the client will ultimately see
  513.          * the wrong status...
  514.          */
  515.         r->status = REDIRECT;
  516.         table_set (r->headers_out, "Location", custom_response);
  517.     } else if ( custom_response[0] == '/') {
  518.         r->no_cache = 1;    /* Do NOT send USE_LOCAL_COPY for
  519.                  * error documents!
  520.                  */
  521.         internal_redirect (custom_response, r);
  522.         return;
  523.     } else {
  524.         /* Dumb user has given us a bad url to redirect to
  525.          * --- fake up dying with a recursive server error...
  526.          */
  527.         recursive_error = SERVER_ERROR;
  528.         log_reason("Invalid error redirection directive", custom_response,
  529.                r);
  530.     }       
  531.     }
  532.  
  533.     send_error_response (r, recursive_error);
  534. }
  535.  
  536. static void decl_die (int status, char *phase, request_rec *r)
  537. {
  538.     if (status == DECLINED) {
  539.     log_reason (pstrcat (r->pool,
  540.                  "configuration error:  couldn't ",
  541.                  phase, NULL),
  542.             r->uri,
  543.             r);
  544.     die (SERVER_ERROR, r);
  545.     }
  546.     else die (status, r);
  547. }
  548.  
  549. void process_request_internal (request_rec *r)
  550. {
  551.     int access_status;
  552.   
  553.     /* Kludge to be reading the assbackwards field outside of protocol.c,
  554.      * but we've got to check for this sort of nonsense somewhere...
  555.      */
  556.     
  557.     if (r->assbackwards && r->header_only) {
  558.     /* Client asked for headers only with HTTP/0.9, which doesn't
  559.      * send headers!  Have to dink things even to make sure the
  560.      * error message comes through...
  561.      */
  562.     log_reason ("client sent illegal HTTP/0.9 request", r->uri, r);
  563.     r->header_only = 0;
  564.     die (BAD_REQUEST, r);
  565.     return;
  566.     }
  567.     
  568.     access_status = unescape_url(r->uri);
  569.     if (access_status)
  570.     {
  571.     die(access_status, r);
  572.     return;
  573.     }
  574.  
  575.     getparents(r->uri);        /* OK --- shrinking transformations... */
  576.  
  577.     if ((access_status = translate_name (r))) {
  578.         decl_die (access_status, "translate", r);
  579.     return;
  580.     }
  581.     
  582.     if ((access_status = directory_walk (r))) {
  583.         die (access_status, r);
  584.     return;
  585.     }    
  586.     
  587.     if ((access_status = check_access (r)) != 0) {
  588.         decl_die (access_status, "check access", r);
  589.     return;
  590.     }
  591.     
  592.     if (auth_type (r)) {
  593.         if ((access_status = check_user_id (r)) != 0) {
  594.         decl_die (access_status, "check user.  No user file?", r);
  595.         return;
  596.     }
  597.  
  598.     if ((access_status = check_auth (r)) != 0) {
  599.         decl_die (access_status, "check access.  No groups file?", r);
  600.         return;
  601.     }
  602.     }
  603.  
  604.     if ((access_status = find_types (r)) != 0) {
  605.         decl_die (access_status, "find types", r);
  606.     return;
  607.     }
  608.  
  609.     if ((access_status = run_fixups (r)) != 0) {
  610.         die (access_status, r);
  611.     return;
  612.     }
  613.  
  614.     if ((access_status = invoke_handler (r)) != 0)
  615.         die (access_status, r);
  616. }
  617.  
  618. void process_request (request_rec *r)
  619. {
  620.     process_request_internal (r);
  621.     log_transaction (r);
  622. }
  623.  
  624. table *rename_original_env (pool *p, table *t)
  625. {
  626.     array_header *env_arr = table_elts (t);
  627.     table_entry *elts = (table_entry *)env_arr->elts;
  628.     table *new = make_table (p, env_arr->nelts);
  629.     int i;
  630.     
  631.     for (i = 0; i < env_arr->nelts; ++i) {
  632.         if (!elts[i].key) continue;
  633.     table_set (new, pstrcat (p, "REDIRECT_", elts[i].key, NULL),
  634.            elts[i].val);
  635.     }
  636.  
  637.     return new;
  638. }
  639.  
  640. void internal_redirect (char *new_uri, request_rec *r)
  641. {
  642.     request_rec *new = (request_rec *)pcalloc(r->pool, sizeof(request_rec));
  643.     char t[10];            /* Long enough... */
  644.   
  645.     new->connection = r->connection;
  646.     new->server = r->server;
  647.     new->pool = r->pool;
  648.     
  649.     /* A whole lot of this really ought to be shared with protocol.c...
  650.      * another missing cleanup.  It's particularly inappropriate to be
  651.      * setting header_only, etc., here.
  652.      */
  653.     
  654.     parse_uri (new, new_uri);
  655.     new->request_config = create_request_config (r->pool);
  656.     new->per_dir_config = r->server->lookup_defaults;
  657.     
  658.     new->prev = r;
  659.     r->next = new;
  660.     
  661.     /* We are redirecting.  Treat the internally generated transaction
  662.      * as a GET, since there is not a chance of its getting POST-style
  663.      * arguments.   
  664.      */
  665.     new->method = "GET";
  666.     new->method_number = M_GET;
  667.  
  668.     /* Inherit the rest of the protocol info... */
  669.     
  670.     new->status = r->status;
  671.     new->assbackwards = r->assbackwards;
  672.     new->header_only = r->header_only;
  673.     new->protocol = r->protocol;
  674.     new->main = r->main;
  675.  
  676.     new->headers_in = r->headers_in;
  677.     new->headers_out = make_table (r->pool, 5);
  678.     new->err_headers_out = r->err_headers_out;
  679.     new->subprocess_env = rename_original_env (r->pool, r->subprocess_env);
  680.     new->notes = make_table (r->pool, 5);
  681.     
  682.     new->no_cache = r->no_cache; /* If we've already made up our minds
  683.                   * about this, don't change 'em back!
  684.                   */
  685.  
  686.     sprintf (t, "%d", r->status);
  687.     table_set (new->subprocess_env, "REDIRECT_STATUS", pstrdup (r->pool, t));
  688.  
  689.     process_request_internal (new);
  690. }
  691.  
  692.